import 'dart:math';
import 'dart:typed_data';

import 'package:bluetooth_parse_plugin/src/utils/byte_utils.dart';
import 'package:crclib/catalog.dart';

class Utils {
  static const int _checkTypeParity = 0x10; // 奇偶校验
  static const int _checkTypeCRC16 = 0x20; // CRC16
  static const int _checkTypeCRC32 = 0x30; // CRC32

  // 生成区间随机数（包min、max）
  static int random(int min, int max) {
    var result = min + Random().nextInt(max + 1 - min);
    return result;
  }

  //int ---> hex
  static String intToHex(int num) {
    String hexString = num.toRadixString(16);
    return hexString;
  }

  //hex ---> int  更简单，加上了容错处理(感谢 @"坐了整个春夏秋冬" 小伙伴的反馈)
  static int hexToInt(String hex) {
    int? val;
    if (hex.toUpperCase().contains("0X")) {
      String desString = hex.substring(2);
      val = int.tryParse("0x$desString");
    } else {
      val = int.tryParse("0x$hex");
    }
    return val ?? 0;
  }

  // Uint8List ---> int
  static int listToInt(Uint8List list) {
    int val = 0;
    for (var i = 0; i < list.length; i++) {
      val += list[i];
    }
    return val;
  }

  static bool equals(Uint8List list1, Uint8List list2) {
    if (list1.length != list2.length) return false;
    for (int i = 0, length = list1.length; i < length; i++) {
      if (list1[i] != list2[i]) return false;
    }
    return true;
  }

  static bool isEvenParityCheck(int format) {
    return (format & _checkTypeParity) == _checkTypeParity && !isCRC32(format);
  }

  static bool isCRC16(int format) {
    return (format & _checkTypeCRC16) == _checkTypeCRC16 && !isCRC32(format);
  }

  static bool isCRC32(int format) {
    return (format & _checkTypeCRC32) == _checkTypeCRC32;
  }

  // 奇偶校验算法
  static Uint8List calculateEvenParity(Uint8List data,
      [int offset = 0, int length = 0]) {
    if (length == 0) length = data.length;
    int result = 0;
    for (int i = offset, max = offset + length; i < max; i++) {
      result ^= data[i];
    }
    Uint8List check = Uint8List(1);
    check[0] = result;
    return check;
  }

  /// CRC32校验算法
  /// 高位在左，低位在右（即小端模式）
  static Uint8List crc32_2(Uint8List data, [int offset = 0, int length = 0]) {
    return ByteUtils.num2BytesLe(Crc32Xz().convert(data).toBigInt().toInt(), 4);
  }

  /// 基于Modbus CRC16的校验算法
  /// 低位在左，高位在右
  static Uint8List crc16(Uint8ClampedList bytes,
      [int offset = 0, int length = 0]) {
    if (length == 0) length = bytes.length;
    if (bytes.isEmpty || bytes.length < offset + length) {
      return Uint8List(0);
    }
    // 预置 1 个 16 位的寄存器为十六进制FFFF, 称此寄存器为 CRC寄存器。
    int crc = 0xFFFF;
    for (int i = offset, max = offset + length; i < max; i++) {
      // 把第一个 8 位二进制数据 与 16 位的 CRC寄存器的低 8 位相异或, 把结果放于 CRC寄存器
      crc = ((crc & 0xFF00) | (crc & 0x00FF) ^ (bytes[i] & 0xFF));
      for (int j = 0; j < 8; j++) {
        // 把 CRC 寄存器的内容右移一位( 朝低位)用 0 填补最高位, 并检查右移后的移出位
        if ((crc & 0x0001) > 0) {
          // 如果移出位为 1, CRC寄存器与多项式A001进行异或
          crc = crc >> 1;
          crc = crc ^ 0xA001;
        } else {
          // 如果移出位为 0,再次右移一位
          crc = crc >> 1;
        }
      }
    }
    return ByteUtils.num2BytesLe(crc, 2);
  }
}
